package com.sky.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.OrderStatistConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.properties.BaiduAddressProperties;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.OrderService;
import com.sky.utils.HttpClientUtil;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.websocket.WebSocketServer;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private BaiduAddressProperties baiduAddressProperties;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 用户下单
     *
     * @param ordersSubmitDTO
     * @return
     */
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) throws IOException {

//        调用获取距离方法
        getDistance(ordersSubmitDTO.getAddressBookId());

        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO, orders);

//        业务异常(地址簿为空，购物车数据为空)
        AddressBook addressBook = AddressBook.builder()
                .id(orders.getAddressBookId())
                .userId(BaseContext.getCurrentId())
                .build();
        AddressBook address = addressBookMapper.selectAddressById(addressBook);
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(BaseContext.getCurrentId())
                .build();
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectAll(shoppingCart);
        if (address == null) {
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        if (shoppingCarts.size() == 0 || shoppingCarts == null) {
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
//        向订单表插入一条数据
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setPhone(address.getPhone());
        orders.setConsignee(address.getConsignee());
        orders.setUserId(BaseContext.getCurrentId());
        orders.setAddress(address.getProvinceName() + address.getCityName() + address.getDistrictName() + address.getDetail());
        orderMapper.insertItem(orders);
//        向订单明细表插入多条数据
        for (ShoppingCart cart : shoppingCarts) {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetailMapper.insertItems(orderDetail);
        }
//        下单成功后清空购物车数据
        shoppingCartMapper.deleteItems(shoppingCart);


        /**
         * 以下替代了微信支付
         */
        //  通过websocket向客户端浏览器推送下单成功消息 type orderId content
        // 根据id查询订单
        Orders ordersDB = orderMapper.selectById(orders);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("type", 1);
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号: "+ ordersDB.getNumber());

        String json = JSONObject.toJSONString(map);
        webSocketServer.sendToAllClient(json);
        //为替代微信支付成功后的数据库订单状态更新，多定义一个方法进行修改
        Integer OrderPaidStatus = Orders.PAID; //支付状态，已支付
        Integer OrderStatus = Orders.TO_BE_CONFIRMED;  //订单状态，待接单

        //发现没有将支付时间 check_out属性赋值，所以在这里更新
        LocalDateTime check_out_time = LocalDateTime.now();

        //获取订单号码
        String orderNumber = ordersDB.getNumber();

        Orders orders1 = Orders.builder()
                .status(OrderStatus)
                .payStatus(OrderPaidStatus)
                .checkoutTime(check_out_time)
                .number(orderNumber)
                .build();
        log.info("调用updateStatus，用于替换微信支付更新数据库状态的问题");
        orderMapper.updateStatusSecond(orders1);



//        封装VO返回结果
        return new OrderSubmitVO(orders.getId(), orders.getNumber(), orders.getAmount(), orders.getOrderTime());
    }

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口，生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额，单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }
//        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
//        vo.setPackageStr(jsonObject.getString("package"));


//      跳过微信支付
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "ORDERPAID");
        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        return vo;
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);

//        通过websocket向客户端浏览器推送下单成功消息 type orderId content
        HashMap<Object, Object> map = new HashMap<>();
        map.put("type", 1);
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号: "+ outTradeNo);

        String json = JSONObject.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

    /**
     * 订单搜索
     *
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        List<Orders> ordersList = orderMapper.selectAllOrders(ordersPageQueryDTO);
        Page pageList = (Page) ordersList;
        return new PageResult(pageList.getTotal(), pageList);
    }

    /**
     * 各个状态订单统计
     *
     * @return
     */
    public OrderStatisticsVO statistics() {
        Integer toBeConfirmed = orderMapper.selectStatus(OrderStatistConstant.TOBECONFIRMED);
        Integer confirmed = orderMapper.selectStatus(OrderStatistConstant.CONFIRMED);
        Integer deliveryInProgress = orderMapper.selectStatus(OrderStatistConstant.DELIVERYINPROGRESS);
        return new OrderStatisticsVO(toBeConfirmed, confirmed, deliveryInProgress);
    }

    /**
     * 查询订单详细
     *
     * @return
     */
    public OrderVO saveDetail(Long id) {
        Orders order = Orders.builder()
                .id(id)
                .build();
        Orders orders = orderMapper.selectById(order);
        OrderDetail orderDetail = OrderDetail.builder()
                .orderId(id)
                .build();
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderDetail);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders, orderVO);
        orderVO.setOrderDetailList(orderDetails);
        return orderVO;
    }

    /**
     * 商家接单
     *
     * @param orders
     */
    public void modifyStatus(Orders orders) {
        orders.setStatus(OrderStatistConstant.CONFIRMED);
        orderMapper.updateStatus(orders);

    }

    /**
     * 商家拒单
     *
     * @param ordersRejectionDTO
     */
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        Orders orders = Orders.builder()
                .id(ordersRejectionDTO.getId())
                .rejectionReason(ordersRejectionDTO.getRejectionReason())
                .status(OrderStatistConstant.REJECT)
                .build();
        orderMapper.updateStatus(orders);
    }

    /**
     * 取消订单
     *
     * @param ordersCancelDTO
     */
    public void cancel(OrdersCancelDTO ordersCancelDTO) {
        Orders orders = Orders.builder()
                .id(ordersCancelDTO.getId())
                .cancelReason(ordersCancelDTO.getCancelReason())
                .status(OrderStatistConstant.CANCEL)
                .build();
        orderMapper.updateStatus(orders);
    }

    /**
     * 派送订单
     *
     * @param id
     */
    public void delivery(Long id) {
        Orders orders = Orders.builder()
                .id(id)
                .status(OrderStatistConstant.DELIVERYINPROGRESS)
                .build();
        orderMapper.updateStatus(orders);
    }

    /**
     * 确认完成订单
     *
     * @param id
     */
    public void complete(Long id) {
        Orders orders = Orders.builder()
                .id(id)
                .status(OrderStatistConstant.COMPLETE)
                .build();
        orderMapper.updateStatus(orders);
    }

    /**
     * 查询历史订单
     *
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult historyOrders(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
//        Orders orders = new Orders();
//        BeanUtils.copyProperties(ordersPageQueryDTO, orders);
        List<Orders> ordersList = orderMapper.selectAllOrders(ordersPageQueryDTO);
        Page pageList = (Page) ordersList;
        return new PageResult(pageList.getTotal(), pageList);
    }

    /**
     * 用户根据id查看订单详细
     *
     * @param id
     * @return
     */
    public OrderVO orderDetail(Long id) {
        Orders order = Orders.builder()
                .id(id)
                .build();
        Orders orders = orderMapper.selectById(order);
        OrderDetail orderDetail = OrderDetail.builder()
                .orderId(id)
                .build();
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderDetail);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders, orderVO);
        orderVO.setOrderDetailList(orderDetails);
        return orderVO;
    }

    /**
     * 用户取消订单
     *
     * @param id
     */
    public void userCancel(Long id) {
        Orders orders = Orders.builder()
                .id(id)
                .status(OrderStatistConstant.CANCEL)
                .build();
        orderMapper.updateStatus(orders);
    }

    /**
     * 用户再来一单
     *
     * @param id
     */
    public void repetition(Long id) {
        OrderDetail orderDetail = OrderDetail.builder()
                .orderId(id)
                .build();
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderDetail);
        for (OrderDetail detail : orderDetails) {
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtils.copyProperties(detail, shoppingCart);
            shoppingCart.setUserId(BaseContext.getCurrentId());
            shoppingCartMapper.insert(shoppingCart);
        }
    }

    /**
     * 客户催单
     * @param id
     */
    public void reminder(Long id) {
//        查询该id在订单表中是否有数据
        Orders orders = Orders.builder()
                .id(id)
                .build();
        Orders selectById = orderMapper.selectById(orders);
        if (selectById == null) {
            throw new OrderBusinessException("未查找到该订单");
        }
//        创建websocket链接
        HashMap<Object, Object> map = new HashMap<>();
        map.put("type", 1);
        map.put("orderId", id);
        map.put("content", "订单号: "+ selectById.getNumber());
        String jsonString = JSONObject.toJSONString(map);
        webSocketServer.sendToAllClient(jsonString);

    }




    /**
     * 获取距离方法
     */
    private void getDistance(Long addressBookId) {
//        获取店铺经纬度坐标
//        查看经纬度坐标(获取地理编码)
        HashMap<String, String> map = new HashMap<>();
        map.put("address", baiduAddressProperties.getAddress());
        map.put("output", "json");
        map.put("ak", baiduAddressProperties.getAk());
        String addressResult = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3/?", map);
//        将返回的String类型数据封装成Object类型
        JSONObject jsonObject = JSONObject.parseObject(addressResult);
        JSONObject addressJSON = jsonObject.getJSONObject("result").getJSONObject("location");
//        获取经度
        String shopLng = addressJSON.getString("lng");
        BigDecimal bigDecimal3 = new BigDecimal(shopLng);
        String scaleShopLng = bigDecimal3.setScale(6, RoundingMode.DOWN).toString();
//        获取纬度
        String shopLat = addressJSON.getString("lat");
        BigDecimal bigDecimal4 = new BigDecimal(shopLat);
        String scaleShopLat = bigDecimal4.setScale(6, RoundingMode.DOWN).toString();
//        获取点单用户经纬度坐标
        AddressBook addressBook1 = AddressBook.builder().id(addressBookId).build();
        AddressBook addressBook2 = addressBookMapper.selectAddressById(addressBook1);
        map.put("address", addressBook2.getProvinceName() + addressBook2.getCityName() + addressBook2.getDistrictName() + addressBook2.getDetail());
        String addressResult2 = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3/?", map);
        JSONObject jsonObject2 = JSONObject.parseObject(addressResult2);
        JSONObject addressJSON2 = jsonObject2.getJSONObject("result").getJSONObject("location");
//        获取经度
        String UserLng = addressJSON2.getString("lng");
        BigDecimal bigDecimal1 = new BigDecimal(UserLng);
        String scaleUserLng = bigDecimal1.setScale(6, RoundingMode.DOWN).toString();
//        获取纬度
        String UserLat = addressJSON2.getString("lat");
        BigDecimal bigDecimal2 = new BigDecimal(UserLat);
        String scaleUserLat = bigDecimal2.setScale(6, RoundingMode.DOWN).toString();
//        获取路线规划
        HashMap<String, String> map1 = new HashMap<>();
        String shopAddress = scaleShopLat + "," + scaleShopLng;
        String UserAddress = scaleUserLat + "," + scaleUserLng;
        map1.put("ak", baiduAddressProperties.getAk());
        map1.put("origin", shopAddress);
        map1.put("destination", UserAddress);
//        调用百度路线规划接口
        String roadSet = HttpClientUtil.doGet("https://api.map.baidu.com/direction/v2/driving?", map1);
        JSONObject jsonObject3 = JSONObject.parseObject(roadSet);
//        获取距离
        JSONObject jsonObject1 = jsonObject3.getJSONObject("result");
        JSONArray jsonArray = jsonObject1.getJSONArray("routes");
        String distance = jsonArray.getJSONObject(0).getString("distance");
//        判断距离是否大于5000米
        if ( Integer.parseInt(distance) > 10000) {
            throw new OrderBusinessException("距离商家过远 下单失败");
        }
    }
}
